#pragma pack(push, 16)

#pragma comment( lib, "glew32s.lib")
#define GLEW_STATIC
#include "inc/GL/glew.h"
#include "stlmodel.h"
#include <GL/gl.h>
#include "src/globalvar.h"

#include <qopengl.h>
#include <qopenglfunctions.h>
#include <qopenglshaderprogram.h>
#include <iostream>
#pragma pack(pop)

int cpyint(const char*& p)
{
    int cpy;
    char* memwriter = (char*)&cpy;
    memcpy(memwriter, p, 4);
    p += 4;
    return cpy;
}
float cpyfloat(const char*& p)
{
    float cpy;
    char * memwriter = (char*)&cpy;
    memcpy(memwriter, p, 4);
        p += 4;
    return cpy;
}

Stlmodel::Stlmodel(QObject *parent) :
    bLoaded(false),
    mVertix(nullptr),
    mVertexCnt(0),
    mTriangleCnt(0),
    mNextModel(nullptr),
    mPrevModel(nullptr),
    mXPos(0),
    mYPos(0),
    mZPos(0),
    mOffsetX(0),
    mOffsetZ(0),
    mOffsetY(0)
{
    this->mStackTransform<<1,0,0,0,
            0,1,0,0,
            0,0,1,0,
            0,0,0,1;


}

Stlmodel::Stlmodel(QString filePath):
    mVertix(nullptr),bLoaded(false),mVertexCnt(0),mTriangleCnt(0),
    mMinx(0),mMaxx(0),mMiny(0),mMaxy(0),mMinz(0),mMaxz(0),
    mNextModel(nullptr),
    mPrevModel(nullptr),
    mXPos(0),
    mYPos(0),
    mZPos(0)
{
    FILE *p = fopen(filePath.toLocal8Bit().data(),"rb");
    if(nullptr == p){
        this->bLoaded = false;
        return;
    }
    this->ReadStlFile(p);
    this->bLoaded = true;
    this->mStackTransform<<1,0,0,0,
            0,1,0,0,
            0,0,1,0,
            0,0,0,1;
}

Stlmodel::~Stlmodel()
{
    free(mVertix);
    gluDeleteQuadric(mQuadric);

}

int Stlmodel::ReadStlFile(FILE* pFile)
{
    long lSize;
    char* buffer;
    size_t result;
    if (pFile == NULL)
    {
        fputs("File error", stderr);
            exit(1);
    }
    /* 获取文件大小 */
    fseek(pFile, 0, SEEK_END);
    lSize = ftell(pFile);
    rewind(pFile);

    /* 分配内存存储整个文件 */
    buffer = (char*)malloc(sizeof(char)*lSize);
    if (buffer == NULL)
    {
        fputs("Memory error", stderr);
        exit(2);
    }

    /* 将文件拷贝到buffer中 */
    result = fread(buffer, 1, lSize, pFile);
    if (result != lSize)
    {
        fputs("Reading error", stderr);
        exit(3);
    }
    /* 结束演示，关闭文件并释放内存 */
    fclose(pFile);
    if (buffer[79]!=0x20)//判断格式
    {
        readASCII(buffer);
    }
    else
    {
        readBinary(buffer);
    }
    free(buffer);
    glewInit();
    this->bLoaded = true;
    glGenBuffersARB(1, &mVBO);
    glBindBufferARB(GL_ARRAY_BUFFER_ARB, mVBO);
    GLfloat *normal3 = new GLfloat[this->VertrexSize()];
    GLfloat  *normal = this->NormalBuffer();

    for(int i = 0; i < this->VertrexSize()/3;i++){
        normal3[3*i] =  normal[i];
        normal3[3*i + 1] =  normal[i];
        normal3[3*i + 2] =  normal[i];
    }
    glBufferDataARB(GL_ARRAY_BUFFER_ARB, this->VertrexSize()*4 + this->VertrexSize()*4, 0, GL_STATIC_DRAW_ARB);
    glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, this->VertrexSize()*4, this->VertrexBuffer());                             // vertex data
    glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, this->VertrexSize()*4, this->VertrexSize()*4,normal3);                             // normal data

    glBindBufferARB(GL_ARRAY_BUFFER_ARB,0);
}


void Stlmodel::Rotate(float anglex,float angley,float anglez)
{
    auto rotate = ::RotateX(anglex)*::RotateY(angley)*::RotateZ(anglez);
    if(bLoaded){
        for(uint32_t i = 0 ;i < mVertexCnt - 9;){
            for(uint32_t z = 0;z < 3;z++){
                auto pos = ::PositionMatrix(mVertix[i + z*3],mVertix[i + z*3 + 1],mVertix[i + z*3 + 2]);
                auto posmove = pos*rotate;
                mVertix[i + z*3] = posmove(0,0);
                mVertix[i + z*3 + 1] = posmove(0,1);
                mVertix[i + z*3 + 2] = posmove(0,2);
            }
            i += 9;
        }
    }
}
GLvoid DrawCircleArea(float cx, float cy, float cz, float r, int num_segments);

void mySolidCylinder( GLUquadric*   quad,
                     GLdouble base,
                     GLdouble top,
                     GLdouble height,
                     GLint slices,
                     GLint stacks )
{
    glColor3f(1.0, 0.0, 0.0);
    gluCylinder(quad, base, top, height, slices, stacks);
    //top
    DrawCircleArea(0.0, 0.0, height, top, slices);
    //base
    DrawCircleArea(0.0, 0.0, 0.0, base, slices);
}

GLvoid DrawCircleArea(float cx, float cy, float cz, float r, int num_segments)
{
    GLfloat vertex[4];

    const GLfloat delta_angle = 2.0*PI/num_segments;
    glBegin(GL_TRIANGLE_FAN);

    vertex[0] = cx;
    vertex[1] = cy;
    vertex[2] = cz;
    vertex[3] = 1.0;
    glVertex4fv(vertex);

    //draw the vertex on the contour of the circle
    for(int i = 0; i < num_segments ; i++)
    {
        vertex[0] = std::cos(delta_angle*i) * r + cx;
        vertex[1] = std::sin(delta_angle*i) * r + cy;
        vertex[2] = cz;
        vertex[3] = 1.0;
        glVertex4fv(vertex);
    }

    vertex[0] = 1.0 * r + cx;
    vertex[1] = 0.0 * r + cy;
    vertex[2] = cz;
    vertex[3] = 1.0;
    glVertex4fv(vertex);
    glEnd();
}

void RenderBone(float x0, float y0, float z0, float x1, float y1, float z1,double iradius )
{
    GLdouble  dir_x = x1 - x0;
    GLdouble  dir_y = y1 - y0;
    GLdouble  dir_z = z1 - z0;
    GLdouble  bone_length = sqrt( dir_x*dir_x + dir_y*dir_y + dir_z*dir_z );
    static GLUquadricObj *  quad_obj = NULL;
    if ( quad_obj == NULL )
        quad_obj = gluNewQuadric();
    gluQuadricDrawStyle( quad_obj, GLU_FILL );
    gluQuadricNormals( quad_obj, GLU_SMOOTH );
    glPushMatrix();
    // 平移到起始点
    glTranslated( x0, y0, z0 );
    // 计算长度
    double  length;
    length = sqrt( dir_x*dir_x + dir_y*dir_y + dir_z*dir_z );
    if ( length < 0.0001 ) {
        dir_x = 0.0; dir_y = 0.0; dir_z = 1.0;  length = 1.0;
    }
    dir_x /= length;  dir_y /= length;  dir_z /= length;
    GLdouble  up_x, up_y, up_z;
    up_x = 0.0;
    up_y = 1.0;
    up_z = 0.0;
    double  side_x, side_y, side_z;
    side_x = up_y * dir_z - up_z * dir_y;
    side_y = up_z * dir_x - up_x * dir_z;
    side_z = up_x * dir_y - up_y * dir_x;
    length = sqrt( side_x*side_x + side_y*side_y + side_z*side_z );
    if ( length < 0.0001 ) {
        side_x = 1.0; side_y = 0.0; side_z = 0.0;  length = 1.0;
    }
    side_x /= length;  side_y /= length;  side_z /= length;
    up_x = dir_y * side_z - dir_z * side_y;
    up_y = dir_z * side_x - dir_x * side_z;
    up_z = dir_x * side_y - dir_y * side_x;
    // 计算变换矩阵
    GLdouble  m[16] = { side_x, side_y, side_z, 0.0,
        up_x,   up_y,   up_z,   0.0,
        dir_x,  dir_y,  dir_z,  0.0,
        0.0,    0.0,    0.0,    1.0 };
    glMultMatrixd( m );
    // 圆柱体参数
    GLdouble radius= GLdouble(iradius);		// 半径
    GLdouble slices = 12.0;		//	段数
    GLdouble stack = 3.0;		// 递归次数
    gluCylinder( quad_obj, radius, radius, bone_length, slices, stack );
    glPopMatrix();

}

int Stlmodel::ShowStlModelVBO() {

    glPushMatrix();
    glLoadIdentity();
    // Draw connecting rod
    if(this->mNextModel != nullptr){
        glColor3f(0.7, 0.7, 1.0);
        RenderBone(mNextModel->PosX(),mNextModel->PosY(),mNextModel->PosZ(),
                   PosX(),PosY(),PosZ(),0.5);
    }else{
        glColor3f(0.9, 0.9, 1.0);
        RenderBone(mPrevModel->PosX(),mPrevModel->PosY(),mPrevModel->PosZ(),
                   PosX(),PosY(),PosZ(),0.5);
    }
    if(this->mPrevModel == nullptr){
        glColor3f(0.7, 0.7, 1.0);
        RenderBone(0,0,0,
                   PosX(),PosY(),PosZ(),0.5);
    }
    if(this->mPrevModel != nullptr){
        mStackTransform = this->mPrevModel->DhTransform();
    }
//    glBindBufferARB(GL_ARRAY_BUFFER_ARB, this->mVBO);//绑定vbo

//    glEnableClientState(GL_VERTEX_ARRAY);//启用顶点数组属性
//    glVertexPointer(3, GL_FLOAT, 0, 0);//如何解析vbo中数据
//    glEnableClientState(GL_NORMAL_ARRAY);
//    glNormalPointer(GL_FLOAT, 0, (void *)sizeof(this->VertrexSize()*4));

//    glDrawArrays(GL_TRIANGLES, 0, this->mVertexCnt/3);
//    glBindBufferARB(GL_ARRAY_BUFFER_ARB,0);//解除绑定

    multMatrixf(mStackTransform);

    glColor3f(1.0, 0.0, 0.0);
    // Draw the joints
    RenderBone(0,0,-3.0,0,0,3.0,1);
    // draw coordinate
    glBegin(GL_LINES);
    glColor3f(1.0, 0.0, 0.0);
    glVertex3f(0,0,0);
    glVertex3f(10.0, 0,0);
    glColor3f(0, 1.0, 0.0);
    glVertex3f(0,0,0);
    glVertex3f(0,10.0,0);
    glColor3f(1.0, 1.0, 0.0);
    glVertex3f(0,0,0);
    glVertex3f(0,0,10);
    glEnd();

    // if this is the end joint, draw the end point
    if(this->mNextModel == nullptr){
        multMatrixf(this->ATransform());
        glBegin(GL_LINES);
        glColor3f(1.0, 0.0, 0.0);
        glVertex3f(0,0,0);
        glVertex3f(10.0, 0,0);
        glColor3f(0, 1.0, 0.0);
        glVertex3f(0,0,0);
        glVertex3f(0,10.0,0);
        glColor3f(1.0, 1.0, 1.0);
        glVertex3f(0,0,0);
        glVertex3f(0,0,10);
        glEnd();
    }
    glPopMatrix();

    return 0;
}

void Stlmodel::MoveToOriginCordinary(float x, float y, float zIN){
    if(bLoaded){
        for(uint32_t i = 0 ;i < mVertexCnt - 9;){
            for(uint32_t z = 0;z < 3;z++){
                auto pos = ::PositionMatrix41(mVertix[i + z*3],mVertix[i + z*3 + 1],mVertix[i + z*3 + 2]);
                auto posmove = ::Move(x,y,zIN)*pos;

                mVertix[i + z*3] = posmove(0,0);
                mVertix[i + z*3 + 1] = posmove(1,0);
                mVertix[i + z*3 + 2] = posmove(2,0);
            }
            i += 9;
        }
    }
    this->mXPos = x;
    this->mYPos = y;
    this->mZPos = zIN;
}

void Stlmodel::Move(float x, float y, float zIN){
    if(bLoaded){
        for(uint32_t i = 0 ;i < mVertexCnt - 9;){
            for(uint32_t z = 0;z < 3;z++){
                auto pos = ::PositionMatrix41(mVertix[i + z*3],mVertix[i + z*3 + 1],mVertix[i + z*3 + 2]);
                auto posmove = ::Move(x,y,zIN)*pos;

                mVertix[i + z*3] = posmove(0,0);
                mVertix[i + z*3 + 1] = posmove(1,0);
                mVertix[i + z*3 + 2] = posmove(2,0);
            }
            i += 9;
        }
    }
}

void Stlmodel::RotateAxis(float theta){
    Matrix44f transform  = ::Origin();
    float posx = 0;
    float posy = 0;
    float posz = 0;

    float ax = 0;
    float ay = 0;
    float az = 0;
    float alpha = 0;
    float omega = 0;

    if(this->mPrevModel != nullptr){
        // this join axis is depending on the previos joint position
        ax = this->mPrevModel->DhTransform()(0,2);
        ay = this->mPrevModel->DhTransform()(1,2);
        az = this->mPrevModel->DhTransform()(2,2);

        posx = this->mPrevModel->DhTransform()(0,3);
        posy = this->mPrevModel->DhTransform()(1,3);
        posz = this->mPrevModel->DhTransform()(2,3);

        alpha = atan2(ay,ax);
        omega = atan2(sqrt(ay*ay+ax*ax),az);
        transform = transform*::Move(-posx,-posy,-posz);
    }else{
        //fist joint the z-axis is original axis
        ax = 0;
        ay = 0;
        az = 1;
        alpha = 0;
        omega = 0;
    }

    //todo rotate z for alpha
    transform = transform*::RotateZ(-alpha);
    // todo rotate y for omega
    transform = transform*::RotateY(-omega);
    //todo rotate z for theta angle
    transform = transform*::RotateZ(theta/360*2*PI);

    this->mTheta += theta/360*2*PI;
    int32_t tmp = int32_t((this->mTheta * 360)/2/PI);
    tmp = tmp/360;
    mTheta = mTheta - tmp*(2*PI);
    // todo rotate back to z-axis
    transform = transform*::RotateY(omega);
    transform = transform*::RotateZ(alpha);
    // move back to original cordinary
    transform = transform*::Move(posx,posy,posz);
    this->TransformVBO(transform);
    // todo moveo back to origin cordinate
    // if this child link is not empty just rotate it for theta angle
    auto childLink = this->mNextModel;
    int i = 1;
    while(childLink != nullptr) {
        qDebug()<<"link "<<i;
        childLink->RotateWithLine(theta,ax,ay,az);
        i++;
        childLink = childLink->mNextModel;
    }
}

void Stlmodel::RotateWithLine(float theta, float ax, float ay, float az)
{
    qDebug()<<"Prev joint result"<< this->mPrevModel->PosX()
           <<this->mPrevModel->PosY()
           <<this->mPrevModel->PosZ();
    if(this->mXPos != this->mPrevModel->PosX()){
        qDebug()<<"prev joint result:"<< this->mXPos
               <<this->mYPos
               <<this->mZPos;
    }
    auto transform  = ::Origin();

    transform  = transform*::Move(-this->mXPos,
                        -this->mYPos ,
                        -this->mZPos);

    float alpha = atan2(ay,ax);
    float omega = atan2(sqrt(ay*ay+ax*ax),az);

    //todo rotate x for alpha
    transform = transform*::RotateZ(-alpha);

    // todo rotate y for omega
    transform = transform*::RotateY(-omega);
    //std::cout<<"rotate y"<<std::endl<<transform<<std::endl;
    //todo rotate z for theta angle
    transform = transform*::RotateZ(theta/360*2*PI);

    // todo rotate back to z-axis
    transform = transform*::RotateY(omega);
    //std::cout<<"rotate y back"<<std::endl<<transform<<std::endl;
    transform = transform*::RotateZ(alpha);
    //std::cout<<"rotate z back"<<std::endl<<transform<<std::endl;

    // move back to original cordinary
    transform = transform*::Move(this->mPrevModel->PosX() ,
                       this->mPrevModel->PosY() ,
                       this->mPrevModel->PosZ());

    this->TransformVBO(transform);
    this->mXPos = this->mPrevModel->PosX();
    this->mYPos = this->mPrevModel->PosY();
    this->mZPos = this->mPrevModel->PosZ();

    // todo moveo back to origin cordinate
}

void Stlmodel::Transform(Matrix44f transf)
{
    if(bLoaded){
        for(uint32_t i = 0 ;i < mVertexCnt - 9;){
            for(uint32_t z = 0;z < 3;z++){
                auto pos = ::PositionMatrix41(mVertix[i + z*3],mVertix[i + z*3 + 1],mVertix[i + z*3 + 2]);
                auto posmove = transf*pos;
                mVertix[i + z*3] = posmove(0,0);
                mVertix[i + z*3 + 1] = posmove(1,0);
                mVertix[i + z*3 + 2] = posmove(2,0);
            }
            i += 9;
        }
        //todo origin cordinate should be excute;
        auto pos = ::PositionMatrix41(this->mXPos,
                                      this->mYPos,
                                      this->mZPos);

        auto posmove = transf*pos;
    }
}

void Stlmodel::TransformVBO(Matrix44f transf)
{

    this->mStackTransform = mStackTransform*transf;
}


uint32_t Stlmodel::VertrexSize()
{
    return this->mVertexCnt;
}

uint32_t Stlmodel::TriangleSize()
{
    return mTriangleCnt;
}

void Stlmodel::_setMaxAndMin(float x, float y, float z)
{
    if(x > this->mMaxx){
        mMaxx = x;
    }
    if(x < this->mMinx){
        mMinx = x;
    }
    if(y > this->mMaxy){
        mMaxy = y;
    }
    if(y < this->mMiny){
        mMiny = y;
    }
    if(z > this->mMaxz){
        mMaxz = z;
    }
    if(z < this->mMinz){
        mMinz = z;
    }
}

float *Stlmodel::VertrexBuffer()
{
    return this->mVertix;
}

void Stlmodel::SetView()
{
    float wf = mMaxx - mMinx;
    float hf = this->mMaxy - this->mMiny;
    float df = mMaxz - mMinz;
    float diag = sqrt(wf*wf + hf*hf + df*df);
    glOrtho(-0.5*diag, +0.5*diag, -0.5*diag, +0.5*diag, 2.0, 2.0+2*diag);
    glTranslatef(0.0f, 0.0f, -2.0f-diag);
}

float Stlmodel::YSize()
{
    return this->mMaxy - mMiny;
}

void Stlmodel::SetPosition(float x, float y, float z)
{
    this->mXPos = x;
    this->mYPos = y;
    this->mZPos = z;
}



void Stlmodel::SetDHPara(double a, double d, double alpha, double theta)
{
    this->mAlpha = alpha;
    this->mTheta = theta;
    this->mTwist = a;
    this->mDistance = d;
}

Matrix44f Stlmodel::DhTransform()
{
    Matrix44f ret;
    ret<<   cos(mTheta),-sin(mTheta)*cos(mAlpha),sin(mTheta)*sin(mAlpha),mTwist*cos(mTheta),
    sin(mTheta),cos(mTheta)*cos(mAlpha),-sin(mAlpha)*cos(mTheta),mTwist*sin(mTheta),
    0,sin(mAlpha),cos(mAlpha),mDistance,
    0,0,0,1;
    if(this->mPrevModel != nullptr){
        return this->mPrevModel->DhTransform()*ret;
    }else{
        return ret;
    }
}

Matrix44f Stlmodel::ATransform()
{
    Matrix44f ret;
    ret<<   cos(mTheta),-sin(mTheta)*cos(mAlpha),sin(mTheta)*sin(mAlpha),mTwist*cos(mTheta),
    sin(mTheta),cos(mTheta)*cos(mAlpha),-sin(mAlpha)*cos(mTheta),mTwist*sin(mTheta),
    0,sin(mAlpha),cos(mAlpha),mDistance,
    0,0,0,1;
    return ret;
}

Matrix44f Stlmodel::StackTransform()
{
    return this->mStackTransform;
}

void Stlmodel::SetPrevModel(Stlmodel *prev)
{
    this->mPrevModel = prev;
}

void Stlmodel::SetNextModel(Stlmodel *next)
{
    if(nullptr == next){
        return;
    }
    next->SetPrevModel(this);
    mNextModel = next;
    next->SetPosition(this->DhTransform()(0,3),
                      this->DhTransform()(1,3),
                      this->DhTransform()(2,3));
}

void Stlmodel::SetTheta(float theta)
{
    this->mTheta = theta;
}

void Stlmodel::SetThetaRadian(float radian)
{
    this->mTheta = radian/360*2*PI;
}



double Stlmodel::Theta()
{
    return mTheta;
}

double Stlmodel::Distance()
{
    return mDistance;
}

double Stlmodel::Twist()
{
    return mTwist;
}

double Stlmodel::PosX()
{
    return this->DhTransform()(0,3);
}
double Stlmodel::PosY()
{
    return this->DhTransform()(1,3);
}
double Stlmodel::PosZ()
{
    return this->DhTransform()(2,3);
}

float *Stlmodel::NormalBuffer()
{
   return this->mNorm;
}
void Stlmodel::initializeGL()
{

}
void Stlmodel::setMinMax(float x, float y, float z)
{
    this->mMinx = x;
    this->mMaxx = x;
    this->mMaxy = y;
    this->mMiny = y;
    this->mMaxz = z;
    this->mMinz = z;

}

void Stlmodel::multMatrixf(Matrix44f ma)
{
    GLfloat   matrix[16];
    matrix[0] = ma(0,0);
    matrix[1] = ma(1,0);
    matrix[2] = ma(2,0);
    matrix[3] = ma(3,0);
    matrix[4] = ma(0,1);
    matrix[5] = ma(1,1);
    matrix[6] = ma(2,1);
    matrix[7] = ma(3,1);
    matrix[8] = ma(0,2);
    matrix[9] = ma(1,2);
    matrix[10] = ma(2,2);
    matrix[11] = ma(3,2);
    matrix[12] = ma(0,3);
    matrix[13] = ma(1,3);
    matrix[14] = ma(2,3);
    matrix[15] = ma(3,3);

    glMultMatrixf(matrix);
}

bool Stlmodel::readASCII(const char *buffer)
{
    int unTriangles = 0;
    float x, y, z;
    int i;
    string name, useless;
    std::stringstream ss(buffer);
    ss >> name >> name;
    ss.get();
    do {
        ss >> useless;
        if (useless != "facet")
            break;
        getline(ss, useless);
        getline(ss, useless);
        for (i = 0; i < 3; i++)
        {
            ss >> useless >> x >> y >> z;
            //pointList.push_back(Point3f(x, y, z));
        }
        unTriangles++;
        getline(ss, useless);
        getline(ss, useless);
        getline(ss, useless);
    }while (1);
    return true;
}

bool Stlmodel::readBinary(const char *buffer)
{
    const char* p = buffer;
    char name[80];
    int i, j;
    memcpy(name, p, 80);
    p += 80;
    int unTriangles = cpyint(p);
    qDebug()<<"unTriangles count "<< unTriangles;
    this->mVertix = new float[unTriangles*9];  //所有的三角面信息
    this->mNorm = new float[unTriangles*3];  //三角面的头部法矢量

    uint32_t  z = 0;
    mTriangleCnt = unTriangles;
    bool first = true;
    for (i = 0; i < unTriangles; i++)
    {
        //p += 12;//跳过头部法向量
        this->mNorm[i*3] = cpyfloat(p) / 10 + this->mOffsetX;
        this->mNorm[i*3 + 1] = cpyfloat(p) /10 + this->mOffsetY;
        this->mNorm[i*3 + 2] = cpyfloat(p)/10 + this->mOffsetZ;

        TriAnlge triangle;
        for (j = 0; j < 3; j++){//读取三顶点
            Vertex x = {cpyfloat(p)/10,cpyfloat(p)/10,cpyfloat(p)/10};

            this->mVertix[z++] = x.x + this->mOffsetX;   //x
            this->mVertix[z++] = x.y + this->mOffsetY;   //y
            this->mVertix[z++] = x.z + this->mOffsetZ;   //z

            if(first){
                setMinMax(x.x/10,x.y/10,x.z/10);
                first = false;
            }
            _setMaxAndMin(x.x/10,x.y/10,x.z/10);
        }
        p += 2;//跳过尾部标志
    }
    mVertexCnt = unTriangles*9;
    return true;
}

